home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / win / c / fixds.com / FIXDS.C next >
Encoding:
C/C++ Source or Header  |  1990-02-02  |  10.0 KB  |  404 lines

  1. //---------------------------------------------------------------------------
  2. // FixDS.c
  3. //---------------------------------------------------------------------------
  4. // Changes the function prologs for all FAR functions in a Windows
  5. // application .EXE file to begin with "mov ax, ss".
  6. // Since SS == DS in an application, this is all that is need for any FAR
  7. // function.  This eliminates the need for the EXPORTS and MakeProcInstance()
  8. // nonsense that Windows programmers have had to fuss with all these years.
  9. //---------------------------------------------------------------------------
  10. // Version 2.2, February 1990
  11. // Removed -d option.
  12. // Version 2.1, May 1989
  13. // Added -d option for special DGROUP hack.
  14. // Version 2.0, February 1989
  15. // Changed it to operate on the .EXE file instead of .OBJ files for
  16. // better reliability.
  17. //---------------------------------------------------------------------------
  18. // Public domain software
  19. // Written by Michael Geary
  20. //---------------------------------------------------------------------------
  21.  
  22. #include <dos.h>
  23. #include <fcntl.h>
  24. #include <malloc.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28.  
  29. #define NEAR            near
  30. #define FAR             far
  31. #define VOID            void
  32.  
  33. typedef char            CHAR;
  34. typedef unsigned char   BYTE;
  35. typedef short           SHORT;
  36. typedef unsigned short  USHORT;
  37. typedef int             INT;
  38. typedef unsigned int    UINT;
  39. typedef long            LONG;
  40. typedef unsigned long   ULONG;
  41. typedef int             HFILE;
  42.  
  43. typedef CHAR   NEAR *   NPCHAR;
  44. typedef BYTE   NEAR *   NPBYTE;
  45. typedef SHORT  NEAR *   NPSHORT;
  46. typedef USHORT NEAR *   NPUSHORT;
  47. typedef INT    NEAR *   NPINT;
  48. typedef UINT   NEAR *   NPUINT;
  49. typedef LONG   NEAR *   NPLONG;
  50. typedef ULONG  NEAR *   NPULONG;
  51. typedef VOID   NEAR *   NPVOID;
  52.  
  53. typedef CHAR   FAR  *   PCHAR;
  54. typedef BYTE   FAR  *   PBYTE;
  55. typedef SHORT  FAR  *   PSHORT;
  56. typedef USHORT FAR  *   PUSHORT;
  57. typedef INT    FAR  *   PINT;
  58. typedef UINT   FAR  *   PUINT;
  59. typedef LONG   FAR  *   PLONG;
  60. typedef ULONG  FAR  *   PULONG;
  61. typedef VOID   FAR  *   PVOID;
  62.  
  63. typedef UINT            BOOL;
  64. typedef UINT            FIELD;
  65.  
  66. typedef CHAR            SZ;
  67. typedef NPCHAR          NPSZ;
  68. typedef PCHAR           PSZ;
  69.  
  70. #define TRUE    1
  71. #define FALSE   0
  72.  
  73. #define loop    for(;;)
  74.  
  75. //---------------------------------------------------------------------------
  76.  
  77. typedef struct _NEWEXE
  78. {
  79.     USHORT      magic;
  80.     USHORT      versionLink;
  81.     USHORT      offEntryTbl;
  82.     USHORT      cbEntryTbl;
  83.     ULONG       crc32;
  84.     USHORT      flags;
  85.     USHORT      dgroup;
  86.     USHORT      cbHeap;
  87.     USHORT      cbStack;
  88.     ULONG       cs_ip;
  89.     ULONG       ss_sp;
  90.     USHORT      nSegs;
  91.     USHORT      nModuleRefs;
  92.     USHORT      cbNonResNames;
  93.     USHORT      offSegTbl;
  94.     USHORT      offResourceTbl;
  95.     USHORT      offResNameTbl;
  96.     USHORT      offModuleRefTbl;
  97.     USHORT      offImportNameTbl;
  98.     LONG        offNonResNameTbl;
  99.     USHORT      nMovableEntries;
  100.     USHORT      shiftcountSector;
  101.     USHORT      nResourceSegs;
  102.     USHORT      offSegCksums;
  103.     USHORT      offReturnThunks;
  104.     USHORT      offSegRefBytes;
  105.     USHORT      nkSwapSize;
  106.     USHORT      versionApp;
  107. }
  108. NEWEXE;
  109.  
  110. typedef NEWEXE NEAR * NPNEWEXE;
  111. typedef NEWEXE FAR  *  PNEWEXE;
  112.  
  113. //---------------------------------------------------------------------------
  114.  
  115. typedef struct _SEGINFO
  116. {
  117.     USHORT      sectorFile;
  118.     USHORT      cbFile;
  119.     struct
  120.     {
  121.       FIELD     segtype:3;
  122.       FIELD     otherflags:5;
  123.     }           flags;
  124.     USHORT      cbAlloc;
  125. }
  126. SEGINFO;
  127.  
  128. typedef SEGINFO NEAR * NPSEGINFO;
  129. typedef SEGINFO FAR  *  PSEGINFO;
  130.  
  131. // Values for seginfo.flags.type:
  132.  
  133. #define CODETYPE 0
  134. #define DATATYPE 1
  135.  
  136. //---------------------------------------------------------------------------
  137.  
  138. VOID  FileReadAt( HFILE hf, LONG lPosition, PVOID pData, USHORT cbData );
  139. VOID  FileSeekTo( HFILE hf, LONG lPosition );
  140. VOID  FileWriteAt( HFILE hf, LONG lPosition, PVOID pData, USHORT cbData );
  141. SHORT PatchSeg( PBYTE pMem, USHORT cbSeg );
  142.  
  143. //---------------------------------------------------------------------------
  144.  
  145. VOID cdecl main
  146. (
  147.     SHORT       nArgs,
  148.     NPCHAR      npArgs[]
  149. )
  150. {
  151.     HFILE       hfEXE;
  152.     PBYTE       pMem;
  153.     SHORT       nChanges, nTotalChanges;
  154.     BYTE        oldexe[0x40];
  155.     NEWEXE      newexe;
  156.     NPSEGINFO   npseginfo, npseginfoBase;
  157.     LONG        loffNewExe, loffSeg;
  158.     USHORT      nSeg, cbSegTbl, cbSeg;
  159.  
  160.     // Check for presence of single file name
  161.  
  162.     if( nArgs != 2 )
  163.     {
  164.       printf( "FixDS: Missing or extra parameter\n" );
  165.       exit(1);
  166.     }
  167.  
  168.     // Convert name to upper case for messages
  169.  
  170.     strupr( npArgs[1] );
  171.  
  172.     // Open the file, read and check old EXE header
  173.  
  174.     if( _dos_open( npArgs[1], (int)O_BINARY | O_RDWR, &hfEXE ) )
  175.     {
  176.       printf( "FixDS: Cannot open %s\n", npArgs[1] );
  177.       exit(2);
  178.     }
  179.  
  180.     FileReadAt( hfEXE, 0L, oldexe, sizeof(oldexe) );
  181.  
  182.     if( *(PUSHORT)&oldexe[0] != 0x5A4D )
  183.     {
  184.       printf( "FixDS: %s is not an EXE file\n", npArgs[1] );
  185.       exit(3);
  186.     }
  187.  
  188.     if( *(PUSHORT)&oldexe[0x18] != 0x40 )
  189.     {
  190.       printf( "FixDS: %s is not a Windows EXE file\n", npArgs[1] );
  191.       exit(4);
  192.     }
  193.  
  194.     // Read new EXE header
  195.  
  196.     loffNewExe = *(PLONG)&oldexe[0x3C];
  197.  
  198.     FileReadAt( hfEXE, loffNewExe, &newexe, sizeof(newexe) );
  199.  
  200.     if( newexe.magic != 0x454E )
  201.     {
  202.       printf( "FixDS: %s is not a Windows EXE file\n", npArgs[1] );
  203.       exit(5);
  204.     }
  205.  
  206.     // Allocate and read segment table
  207.  
  208.     cbSegTbl = newexe.nSegs * sizeof(SEGINFO);
  209.     npseginfoBase = npseginfo = malloc( cbSegTbl );
  210.     if( ! npseginfo )
  211.     {
  212.       printf( "FixDS: Cannot allocate memory for segment table\n" );
  213.       exit(6);
  214.     }
  215.  
  216.     FileReadAt( hfEXE, loffNewExe + newexe.offSegTbl, npseginfo, cbSegTbl );
  217.  
  218.     // Allocate 64K buffer for code segments, using DOS call to make sure
  219.     // it's a true segment address (offset = 0).
  220.  
  221.     FP_OFF(pMem) = 0;
  222.     if( _dos_allocmem( 0x1000, &FP_SEG(pMem) ) )
  223.     {
  224.       printf( "FixDS: Cannot allocate memory for segment buffer\n" );
  225.       exit(7);
  226.     }
  227.  
  228.     // Now read each segment and patch it
  229.  
  230.     nTotalChanges = 0;
  231.  
  232.     for( nSeg = 1;  nSeg <= newexe.nSegs;  nSeg++, npseginfo++ )
  233.     {
  234.       switch( npseginfo->flags.segtype )
  235.       {
  236.         case CODETYPE:
  237.           cbSeg = npseginfo->cbFile;
  238.           if( ! cbSeg )
  239.             cbSeg = 0xFFFF;  // we can round 64K down to 65535
  240.  
  241.           loffSeg = (ULONG)npseginfo->sectorFile << newexe.shiftcountSector;
  242.  
  243.           FileReadAt( hfEXE, loffSeg, pMem, cbSeg );
  244.  
  245.           nChanges = PatchSeg( pMem, cbSeg );
  246.           nTotalChanges += nChanges;
  247.  
  248.           if( nChanges )
  249.             FileWriteAt( hfEXE, loffSeg, pMem, cbSeg );
  250.           break;
  251.       }
  252.     }
  253.  
  254.     // Close the file, report changes, and exit
  255.  
  256.     if( _dos_close( hfEXE ) )
  257.     {
  258.       printf( "FixDS: Error closing %s\n", npArgs[1] );
  259.       exit(8);
  260.     }
  261.  
  262.     printf( "FixDS: Fixed up %d FAR functions\n", nTotalChanges );
  263.     exit(0);
  264. }
  265.  
  266. //---------------------------------------------------------------------------
  267. // Read data from a file at a given offset
  268. //---------------------------------------------------------------------------
  269.  
  270. VOID FileReadAt
  271. (
  272.     HFILE       hf,
  273.     LONG        lPosition,
  274.     PVOID       pData,
  275.     USHORT      cbData
  276. )
  277. {
  278.     UINT        cbResult;
  279.  
  280.     FileSeekTo( hf, lPosition );
  281.  
  282.     if( _dos_read( hf, pData, cbData, &cbResult ) ||
  283.         cbResult != cbData )
  284.     {
  285.         printf( "FixDS: Read Failed\n" );
  286.         exit(11);
  287.     }
  288. }
  289.  
  290. //---------------------------------------------------------------------------
  291. // Seek a file to a given offset from the start.
  292. //---------------------------------------------------------------------------
  293.  
  294. VOID FileSeekTo
  295. (
  296.     HFILE       hf,
  297.     LONG        lPosition
  298. )
  299. {
  300.     union REGS  r;
  301.  
  302.     r.x.ax = 0x4200;  // Seek to absolute position
  303.     r.x.bx = hf;
  304.     r.x.cx = (USHORT)( lPosition >> 16 );
  305.     r.x.dx = (USHORT)( lPosition );
  306.  
  307.     intdos( &r, &r );
  308.  
  309.     if( r.x.cflag )
  310.     {
  311.         printf( "FixDS: Seek Failed\n" );
  312.         exit(10);
  313.     }
  314. }
  315.  
  316. //---------------------------------------------------------------------------
  317. // Write data to a file at a given offset.
  318. //---------------------------------------------------------------------------
  319.  
  320. VOID FileWriteAt
  321. (
  322.     HFILE       hf,
  323.     LONG        lPosition,
  324.     PVOID       pData,
  325.     USHORT      cbData
  326. )
  327. {
  328.     UINT        cbResult;
  329.  
  330.     FileSeekTo( hf, lPosition );
  331.  
  332.     if( _dos_write( hf, pData, cbData, &cbResult ) ||
  333.         cbResult != cbData )
  334.     {
  335.         printf( "FixDS: Write Failed\n" );
  336.         exit(12);
  337.     }
  338. }
  339.  
  340. //---------------------------------------------------------------------------
  341. // Find and patch all FAR function prologs.  These begin with either:
  342. //
  343. // 0x1E   push  ds
  344. // 0x58   pop   ax
  345. //
  346. // or:
  347. //
  348. // 0x8C   mov   ax, ds
  349. // 0xD8    "
  350. //
  351. // or:
  352. //
  353. // 0x90   nop
  354. // 0x90   nop
  355. //
  356. // followed by:
  357. //
  358. // 0x90   nop
  359. // 0x45   inc   bp
  360. // 0x55   push  bp
  361. // 0x8B   mov   bp, sp
  362. // 0xEC    "
  363. // 0x1E   push  ds
  364. // 0x8E   mov   ds, ax
  365. // 0xD8    "
  366. //
  367. // Change the first two bytes of each FAR function to:
  368. //
  369. // 0x8C   mov   ax, ss
  370. // 0xD0   ...
  371. //---------------------------------------------------------------------------
  372.  
  373. SHORT PatchSeg
  374. (
  375.     PBYTE       pMem,
  376.     USHORT      cbSeg
  377. )
  378. {
  379.     SHORT       nChanges;
  380.     PUSHORT     p, pEnd;
  381.  
  382.     nChanges = 0;
  383.  
  384.     for( p = (PUSHORT)pMem,  pEnd = (PUSHORT)(pMem + cbSeg - 10);
  385.          p < pEnd;
  386.          p = (PUSHORT)( (PBYTE)p + 1 ) )
  387.     {
  388.       if( ( p[0] == 0x581E || p[0] == 0xD88C ) &&
  389.             p[1] == 0x4590 &&
  390.             p[2] == 0x8B55 &&
  391.             p[3] == 0x1EEC &&
  392.             p[4] == 0xD88E )
  393.       {
  394.         nChanges++;
  395.         p[0] = 0xD08C;  // mov ax, ss
  396.       }
  397.     }
  398.  
  399.     return nChanges;
  400. }
  401.  
  402. //---------------------------------------------------------------------------
  403.  
  404.